#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/tcp.h>
#include <linux/icmp.h>
#include <linux/if_arp.h>
#include <signal.h>

void print_mac(unsigned char mac[ETH_ALEN]);
void parse_ip(char *buf);
void parse_arp(char *buf);
void parse_tcp(char *buf);
void parse_udp(char *buf);

void handler(int s) {
	printf("按任意键退出...\n");
	getchar();
	exit(0);
}

int main( void ) {
	int fd;
	char buf[2000]; // 获取的以太网帧
	struct tcphdr *tcph;
	struct icmphdr *icmph;
	struct ethhdr *ethh;

	signal(SIGINT, handler);
	
	fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if(fd < 0)
    {
        perror("socket");
        return 0;
    }

	while ( 1 ) {
		int r = read(fd, buf, 2000);
		if ( r <= 0 ) break;
		ethh = (struct ethhdr*)buf;

		print_mac(ethh->h_source);
		printf("--> ");
		print_mac(ethh->h_dest);

		
		short proto = ntohs(ethh->h_proto);
		printf(":%#X ", proto);
		if ( proto == ETH_P_IP ) {
			printf("\n\t");
			parse_ip(buf+sizeof(struct ethhdr));
		} else if ( proto == ETH_P_ARP ) {
			parse_arp(buf+sizeof(struct ethhdr));
		}
		printf("\n");
	}
}

void print_mac(unsigned char mac[ETH_ALEN]) {
	printf("%02X:%02X:%02X:%02X:%02X:%02X ",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
}

void parse_ip(char *buf) {
	struct iphdr *iph = (struct iphdr*)buf;
	struct in_addr dr;
	dr.s_addr = iph->saddr;
	printf("%s ", inet_ntoa(dr));
	dr.s_addr = iph->daddr;
	printf(" -> %s ", inet_ntoa(dr));
	printf("ttl: %d ", iph->ttl);
	printf("protocol: %d ", iph->protocol);
	if ( iph->protocol == IPPROTO_TCP ) {
		printf("\n\t\t");
		parse_tcp(buf+sizeof(struct iphdr));
	} else if ( iph->protocol == IPPROTO_UDP ) {
		printf("\n\t\t");
		parse_udp(buf+sizeof(struct iphdr));
	}
}

void parse_arp(char *buf) {
	struct arphdr *arp = (struct arphdr*)buf;
	printf("ARP包");
}

void parse_tcp(char *buf) {
	struct tcphdr *tcp = (struct tcphdr*)buf;
	printf("%hd : %hd  %u %u ", ntohs(tcp->source), ntohs(tcp->dest), ntohl(tcp->seq), ntohl(tcp->ack_seq));
	if ( tcp->syn != 0 )
		printf("syn ");
	if ( tcp->ack != 0 )
		printf("ack ");
	if ( tcp->fin != 0 )
		printf("fin ");
}

void parse_udp(char *buf) {
	struct udphdr *udp = (struct udphdr*)buf;
	printf("%hd : %hd ", ntohs(udp->source), ntohs(udp->dest));
}

